package com.syqc.monitor.download

import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import com.syqc.comlib.utils.AppContext
import com.syqc.comlib.utils.MLog
import com.syqc.comlib.utils.getParentFile
import okhttp3.*
import java.io.*
import java.net.URLDecoder
import java.util.concurrent.TimeUnit

object DownLoadUtil {
    private val basePath = getParentFile(AppContext.getAppContext()).absolutePath
    val path = "$basePath/gps.apk"
    val pathCczs = "$basePath/gps_cczs.apk"
    val welcomePath = "$basePath/bg_welcome.jpg"
    val loginPath = "$basePath/bg_login.jpg"
    val loginLogoPath = "$basePath/bg_login_logo.jpg"

    private val client by lazy {
        OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .build()
    }
    private var currentCall: Call? = null

    fun downloadFile(url: String, path: String, fileName: String? = null, callback: DownCallback) {
        val clientWithProgress = client.newBuilder()
            .addInterceptor { chain ->
                val response = chain.proceed(chain.request())
                response.newBuilder()
                    .body(FileResponseBody(response.body!!, callback))
                    .build()
            }.build()

        val request = Request.Builder()
            .url(url)
            .addHeader("Accept-Encoding", "identity")
            .addHeader("Connection", "close")
            .build()

        callback.onStart()
        currentCall = clientWithProgress.newCall(request).apply {
            enqueue(object : Callback {
                override fun onFailure(call: Call, e: IOException) {
                    callback.onFailure(e)
                }

                override fun onResponse(call: Call, response: Response) {
                    val finalFileName = fileName ?: extractFileName(response, url)
                    response.body?.use { body ->
                        saveStreamToFile(body.byteStream(), "$path/$finalFileName", callback)
                    }
                }
            })
        }
    }

    fun downloadVideo(url: String, path: String, callback: DownCallback) {
        downloadFile(url, path, null, callback)
    }

    fun downloadImage(url: String, type: String) {
        val path = when (type) {
            "0" -> welcomePath
            "1" -> loginPath
            else -> loginLogoPath
        }
        val request = Request.Builder()
            .url(url)
            .addHeader("Accept-Encoding", "identity")
            .addHeader("Connection", "close")
            .build()

        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                MLog.e("Image download failed: $e")
            }

            override fun onResponse(call: Call, response: Response) {
                response.body?.use {
                    BitmapFactory.decodeStream(it.byteStream())?.saveToFile(path)
                }
            }
        })
    }

    fun cancel() {
        currentCall?.cancel()
    }

    fun saveVideoToSystemAlbum(videoFile: String, context: Context): Boolean {
        return try {
            val resolver = context.contentResolver
            val contentValues = getVideoContentValues(File(videoFile), System.currentTimeMillis())
            val videoUri = resolver.insert(getVideoCollectionUri(), contentValues) ?: return false

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                resolver.openOutputStream(videoUri)?.use { copyFileToStream(videoFile, it) }
            }
            context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, videoUri))
            true
        } catch (e: Exception) {
            MLog.e("Save video failed: $e")
            false
        }
    }

    private fun extractFileName(response: Response, url: String): String {
        val disposition = response.header("Content-Disposition")
        return if (disposition?.contains("filename=") == true) {
            URLDecoder.decode(disposition.substringAfter("filename=").replace("\"", ""), "UTF-8")
        } else {
            URLDecoder.decode(url.split("/").last(), "UTF-8")
        }
    }

    private fun saveStreamToFile(stream: InputStream, path: String, callback: DownCallback) {
        try {
            FileOutputStream(File(path)).use { fos ->
                stream.copyTo(fos, 2048)
                callback.onSuccess(path.split("/").last())
            }
        } catch (e: IOException) {
            callback.onFailure(e)
        }
    }

    private fun Bitmap.saveToFile(path: String) {
        try {
            FileOutputStream(File(path)).use { compress(Bitmap.CompressFormat.PNG, 100, it) }
        } catch (e: IOException) {
            MLog.e("Save bitmap failed: $e")
        }
    }

    private fun copyFileToStream(sourcePath: String, output: OutputStream) {
        FileInputStream(sourcePath).use { it.copyTo(output, 1444) }
    }

    private fun getVideoCollectionUri(): Uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
    } else {
        MediaStore.Video.Media.EXTERNAL_CONTENT_URI
    }

    private fun getVideoContentValues(file: File, timestamp: Long) = ContentValues().apply {
        put(MediaStore.Video.Media.TITLE, file.name)
        put(MediaStore.Video.Media.DISPLAY_NAME, file.name)
        put(MediaStore.Video.Media.MIME_TYPE, "video/mp4")
        put(MediaStore.Video.Media.DATE_TAKEN, timestamp)
        put(MediaStore.Video.Media.DATE_MODIFIED, timestamp)
        put(MediaStore.Video.Media.DATE_ADDED, timestamp)
        put(MediaStore.Video.Media.SIZE, file.length())
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_MOVIES)
            // 确保 DISPLAY_NAME 唯一，例如添加时间戳
            put(MediaStore.Video.Media.DISPLAY_NAME, "${file.nameWithoutExtension}_${timestamp}.${file.extension}")
        }
    }
}